package com.pozu.new_retail.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import com.alibaba.fastjson.JSONObject;
import com.pozu.new_retail.utils.Tools;
import com.pozu.new_retail.dao.pay.wx.WXCallBackInfo;
import com.pozu.new_retail.dao.pay.wx.WXClientPayRequestInfo;
import com.pozu.new_retail.dao.pay.wx.WXPrePayOrder;
import com.pozu.new_retail.dao.pay.wx.WXQueryOrder;

/**
 * 支付工具类
 * @author chao
 * @date 2018年4月20日
 */
public class PayTools {
	
	private static final int SESSION_ID_BYTES = 16;

	/** 微信支付相关常量 **/
	public static String wx_notify_url = PropertiesUtil.getString("wx_notify_url");
	public static String wx_pay_url = PropertiesUtil.getString("wx_pay_url");
	public static String wx_trade_type = PropertiesUtil.getString("wx_trade_type");
	public static String wx_order_query_url = PropertiesUtil.getString("wx_order_query_url");
	public static String wx_sns_url = PropertiesUtil.getString("wx_sns_url");
	public static String wx_sns_grant_type = PropertiesUtil.getString("wx_sns_grant_type");

	private static MessageDigest getDigest() {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			return md;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static synchronized String generateRandCode() {

		Random random = new SecureRandom();
		byte bytes[] = new byte[SESSION_ID_BYTES];
		random.nextBytes(bytes);
		bytes = getDigest().digest(bytes);
		StringBuffer result = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
			byte b2 = (byte) (bytes[i] & 0x0f);
			if (b1 < 10)
				result.append((char) ('0' + b1));
			else
				result.append((char) ('A' + (b1 - 10)));
			if (b2 < 10)
				result.append((char) ('0' + b2));
			else
				result.append((char) ('A' + (b2 - 10)));
		}
		return (result.toString());
	}
	
	/**
	 * 发送post请求
	 * 
	 * @param pathUrl
	 * @param content
	 * @return
	 */
	public static String httpPost(String pathUrl, String content) {
		try {
			// pathUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
			// 建立连接
			URL url = new URL(pathUrl);
			HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();

			// //设置连接属性
			httpConn.setDoOutput(true);// 使用 URL 连接进行输出
			httpConn.setDoInput(true);// 使用 URL 连接进行输入
			httpConn.setUseCaches(false);// 忽略缓存
			httpConn.setRequestMethod("POST");// 设置URL请求方法

			// 设置请求属性
			// 获得数据字节数据，请求数据流的编码，必须和下面服务器端处理请求流的编码一致
			byte[] contentBytes = content.getBytes("UTF-8");
			httpConn.setRequestProperty("Content-length", "" + contentBytes.length);
			httpConn.setRequestProperty("Content-Type", "application/octet-stream");
			httpConn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
			httpConn.setRequestProperty("Charset", "UTF-8");

			// 建立输出流，并写入数据
			OutputStream outputStream = httpConn.getOutputStream();
			outputStream.write(contentBytes);
			outputStream.close();
			// 获得响应状态
			int responseCode = httpConn.getResponseCode();

			if (HttpURLConnection.HTTP_OK == responseCode) {// 连接成功
				// 当正确响应时处理数据
				StringBuffer sb = new StringBuffer();
				String readLine;
				BufferedReader responseReader;
				// 处理响应流，必须与服务器响应流输出的编码一致
				responseReader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), "UTF-8"));
				while ((readLine = responseReader.readLine()) != null) {
					sb.append(readLine).append("\n");
				}
				responseReader.close();
				return sb.toString();
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}

	/***
	 * MD5加密 生成32位md5码
	 * 
	 * @param inStr 待加密字符串
	 * @return 返回32位md5码
	 */
	public static String md5Encode(String inStr) throws Exception {
		MessageDigest md5 = null;
		try {
			md5 = MessageDigest.getInstance("MD5");
		} catch (Exception e) {
			System.out.println(e.toString());
			e.printStackTrace();
			return "";
		}

		byte[] byteArray = inStr.getBytes("UTF-8");
		byte[] md5Bytes = md5.digest(byteArray);
		StringBuffer hexValue = new StringBuffer();
		for (int i = 0; i < md5Bytes.length; i++) {
			int val = ((int) md5Bytes[i]) & 0xff;
			if (val < 16) {
				hexValue.append("0");
			}
			hexValue.append(Integer.toHexString(val));
		}
		return hexValue.toString();
	}

	/**
	 * 获取签名
	 * 
	 * @param order
	 * @return
	 * @throws Exception
	 */
	public static String createWXPrePaySign(WXPrePayOrder order, String wx_key) throws Exception {
		StringBuffer sb = new StringBuffer();
		sb.append("appid=" + order.getAppid() + "&attach=" + order.getAttach() + "&body=" + order.getBody() + "&mch_id="
				+ order.getMch_id() + "&nonce_str=" + order.getNonce_str() + "&notify_url=" + order.getNotify_url()
				+ "&openid=" + order.getOpenid() + "&out_trade_no=" + order.getOut_trade_no() + "&spbill_create_ip="
				+ order.getSpbill_create_ip() + "&total_fee=" + order.getTotal_fee() + "&trade_type="
				+ order.getTrade_type() + "&key=" + wx_key);
		return md5Encode(sb.toString()).toUpperCase();
	}

	/**
	 * 获取签名
	 * 
	 * @param order
	 * @return
	 * @throws Exception
	 */
	public static String createWXQueryOrderSign(WXQueryOrder order, String wx_key) throws Exception {
		StringBuffer sb = new StringBuffer();
		sb.append("appid=" + order.getAppid() + "&mch_id=" + order.getMch_id() + "&nonce_str=" + order.getNonce_str()
				+ "&out_trade_no=" + order.getOut_trade_no() + "&key=" + wx_key);
		return md5Encode(sb.toString()).toUpperCase();
	}

	/**
	 * 获取签名
	 * 
	 * @param wx_key
	 * @return
	 * @throws Exception
	 */
	public static String createWXClientPayRequestSign(WXClientPayRequestInfo info, String wx_key) throws Exception {
		StringBuffer sb = new StringBuffer();
		sb.append("appId=" + info.getAppId() + "&nonceStr=" + info.getNonceStr() + "&package=" + info.getBody()
				+ "&signType=" + info.getSignType() + "&timeStamp=" + info.getTimeStamp() + "&key=" + wx_key);
		return md5Encode(sb.toString()).toUpperCase();
	}

	/**
	 * 获取签名
	 * 
	 * @param wx_key
	 * @return
	 * @throws Exception
	 */
	public static String createWXCallBackInfoSign(WXCallBackInfo info, String wx_key) throws Exception {
		StringBuffer sb = new StringBuffer();
		sb.append("appid=" + info.getAppid() + "&attach=" + info.getAttach() + "&bank_type=" + info.getBank_type()
				+ "&cash_fee=" + info.getCash_fee() + "&fee_type=" + info.getFee_type() + "&is_subscribe="
				+ info.getIs_subscribe() + "&mch_id=" + info.getMch_id() + "&nonce_str=" + info.getNonce_str()
				+ "&openid=" + info.getOpenid() + "&out_trade_no=" + info.getOut_trade_no() + "&result_code="
				+ info.getResult_code() + "&return_code=" + info.getReturn_code() + "&time_end=" + info.getTime_end()
				+ "&total_fee=" + info.getTotal_fee() + "&trade_type=" + info.getTrade_type() + "&transaction_id="
				+ info.getTransaction_id() + "&key=" + wx_key);
		return md5Encode(sb.toString()).toUpperCase();
	}

	/**
	 * 将对象直接转换成String类型的 XML输出
	 * 
	 * @param obj
	 * @return
	 */
	public static String convertToXml(Object obj) {
		// 创建输出流
		StringWriter sw = new StringWriter();
		try {
			// 利用jdk中自带的转换类实现
			JAXBContext context = JAXBContext.newInstance(obj.getClass());

			Marshaller marshaller = context.createMarshaller();
			// 格式化xml输出的格式
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			// 将对象转换成输出流形式的xml
			marshaller.marshal(obj, sw);
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		return sw.toString();
	}

	/**
	 * 将String类型的xml转换成对象
	 * 
	 * @param clazz
	 * @param xmlStr
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static Object convertXmlStrToObject(Class clazz, String xmlStr) {
		Object xmlObject = null;
		try {
			JAXBContext context = JAXBContext.newInstance(clazz);
			// 进行将Xml转成对象的核心接口
			Unmarshaller unmarshaller = context.createUnmarshaller();
			StringReader sr = new StringReader(xmlStr);
			xmlObject = unmarshaller.unmarshal(sr);
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		return xmlObject;
	}

	/**
	 * 发送xml
	 * 
	 * @param response
	 * @param xmlString
	 * @throws Exception
	 */
	public static void sendXML(HttpServletResponse response, String xmlString) throws Exception {
		try {
			response.setContentType("text/xml;charset=UTF-8");
			response.setContentLength(xmlString.getBytes("utf-8").length);
			response.getWriter().write(xmlString);
			response.getWriter().flush();
			response.getWriter().close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
 	/**
 	 * 根据js_code获取openId和uuid
 	 * @param js_code
 	 * @param wx_sns_appid
 	 * @param wx_sns_secret
 	 * @return
 	 */
 	public static Map<String, String> getOpenIdAnUUID(String js_code,String wx_sns_appid,String wx_sns_secret){
 		
 		Map<String, String> map = new HashMap();
 		String url = wx_sns_url+"?appid="+wx_sns_appid+"&secret="+wx_sns_secret+"&js_code="+js_code+"&grant_type="+wx_sns_grant_type;
 		
 		String result = Tools.httpGet(url, null);
 		
 		JSONObject json = JSONObject.parseObject(result);
 		if(null!=json&&json.containsKey("openid")){
 			
 			map.put("openId", json.getString("openid"));
 			if(json.containsKey("unionid")){
 				map.put("uuid", json.getString("unionid"));
 			}
 			
 		}
 		
 		return map;
 	}

}
